{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 图像转换 (图像增强)\n",
    "\n",
    "学习如何使用TensorFlow 2.0应用各种图像增强技术。变换是指在训练时对每个图像样本进行变换，每次变换的参数都是随机的。\n",
    "\n",
    "**变换:**\n",
    "- 随机翻转\n",
    "- 随机对比，亮度，饱和度和色调\n",
    "- 随机失真和裁剪"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import absolute_import, division, print_function\n",
    "\n",
    "from IPython.display import Image as IImage, display\n",
    "import numpy as np\n",
    "import PIL\n",
    "from PIL import Image\n",
    "import random\n",
    "import requests\n",
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取一张网络图片\n",
    "d = requests.get(\"https://www.paristoolkit.com/Images/xeffel_view.jpg.pagespeed.ic.8XcZNqpzSj.jpg\")\n",
    "with open(\"image.jpeg\", \"wb\") as f:\n",
    "    f.write(d.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将图像加载到numpy数组\n",
    "img = PIL.Image.open('image.jpeg')\n",
    "img.load()\n",
    "img_array = np.array(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 显示图片\n",
    "PIL.Image.fromarray(img_array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 随机左右翻转图像\n",
    "# tf.image.flip_up_down：上下翻转\n",
    "# tf.image.flip_left_right：左右翻转\n",
    "# tf.image.transpose_image：对角线翻转\n",
    "# tf.image.random_flip_up_down：随机上下翻转图片\n",
    "# tf.image.random_flip_left_right：随机左右翻转图片\n",
    "def random_flip_left_right(image):\n",
    "    return tf.image.random_flip_left_right(image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 展示随机翻转后的图片\n",
    "PIL.Image.fromarray(random_flip_left_right(img_array).numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 随机更改图像对比度。\n",
    "def random_contrast(image, minval=0.6, maxval=1.4):\n",
    "    # tf.random.uniform()用来生成均匀分布的张量\n",
    "    # shape：一维整数张量或 Python 数组，输出张量的形状.\n",
    "    # minval：生成的随机值范围的下限\n",
    "    # maxval：生成的随机值范围的上限\n",
    "    r = tf.random.uniform([], minval=minval, maxval=maxval)\n",
    "    image = tf.image.adjust_contrast(image, contrast_factor=r)  # contrast_factor对比度因数\n",
    "    return tf.cast(image, tf.uint8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 展示修改对比度之后的图片\n",
    "PIL.Image.fromarray(random_contrast(img_array).numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 随机更改图像亮度\n",
    "def random_brightness(image, minval=0., maxval=.2):\n",
    "    r = tf.random.uniform([], minval=minval, maxval=maxval)\n",
    "    image = tf.image.adjust_brightness(image, delta=r)\n",
    "    return tf.cast(image, tf.uint8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 展示修改亮度后的图片\n",
    "PIL.Image.fromarray(random_brightness(img_array).numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 图像随机更改饱和度\n",
    "def random_saturation(image, minval=0.4, maxval=2.):\n",
    "    r = tf.random.uniform((), minval=minval, maxval=maxval)\n",
    "    image = tf.image.adjust_saturation(image, saturation_factor=r)\n",
    "    return tf.cast(image, tf.uint8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 展示修改饱和度之后的照片\n",
    "PIL.Image.fromarray(random_saturation(img_array).numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 随机更改图像的色调\n",
    "def random_hue(image, minval=-0.04, maxval=0.08):\n",
    "    r = tf.random.uniform((), minval=minval, maxval=maxval)\n",
    "    image = tf.image.adjust_hue(image, delta=r)\n",
    "    return tf.cast(image, tf.uint8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 展示修改色调之后的图片\n",
    "PIL.Image.fromarray(random_hue(img_array).numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 通过以不同的宽高比裁切图像来扭曲图像\n",
    "def distorted_random_crop(image,\n",
    "                min_object_covered=0.1,\n",
    "                aspect_ratio_range=(3./4., 4./3.),\n",
    "                area_range=(0.06, 1.0),\n",
    "                max_attempts=100,\n",
    "                scope=None):\n",
    "\n",
    "    cropbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4])\n",
    "    sample_distorted_bounding_box = tf.image.sample_distorted_bounding_box(\n",
    "        tf.shape(image),\n",
    "        bounding_boxes=cropbox,\n",
    "        min_object_covered=min_object_covered,\n",
    "        aspect_ratio_range=aspect_ratio_range,\n",
    "        area_range=area_range,\n",
    "        max_attempts=max_attempts,\n",
    "        use_image_if_no_bounding_boxes=True)\n",
    "    bbox_begin, bbox_size, distort_bbox = sample_distorted_bounding_box\n",
    "\n",
    "    # 将图像裁剪到指定的边框\n",
    "    cropped_image = tf.slice(image, bbox_begin, bbox_size)\n",
    "    return cropped_image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Display cropped image.\n",
    "PIL.Image.fromarray(distorted_random_crop(img_array).numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这是用于图像数据集（例如ImageNet）的常见图像增强技术\n",
    "def transform_image(image):\n",
    "    image = distorted_random_crop(image)\n",
    "    image = random_flip_left_right(image)\n",
    "    image = random_contrast(image)\n",
    "    image = random_brightness(image)\n",
    "    image = random_hue(image)\n",
    "    image = random_saturation(image)\n",
    "    return image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 显示预处理后的图像\n",
    "transformed_img = transform_image(img_array).numpy()\n",
    "PIL.Image.fromarray(transformed_img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将转换后的图像调整为256x256像素的正方形图像，准备进行训练\n",
    "def resize_image(image):\n",
    "    image = tf.image.resize(image, size=(256, 256), preserve_aspect_ratio=False)\n",
    "    image = tf.cast(image, tf.uint8)\n",
    "    return image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "PIL.Image.fromarray(resize_image(transformed_img).numpy())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
